// C++ Templates: 第13.2节 名称查找
// 在C++模板中，名称查找（Name Lookup）是一个复杂而重要的概念，它决定了编译器如何解析模板中使用的标识符。第13.2节详细讨论了这个主题，以下是其核心内容：

// 13.2 名称查找
// 基本查找规则
// C++中的名称查找遵循一定的规则顺序：
// 1.局部作用域：首先在当前块中查找
// 2.类作用域：如果是类成员函数，则在类中查找
// 3.命名空间作用域：在相关命名空间中查找
// 4.全局作用域：最后在全局作用域中查找

// 依赖名称查找
// 依赖名称的查找规则比较特殊：
// 1.限定依赖名称（Qualified dependent names）：
template <typename T>
void foo()
{
    T::static_member; // 限定依赖名称
}
// 只在T的作用域中查找
// 如果是类型，需要使用typename关键字

// 2.非限定依赖名称（Unqualified dependent names）：
template <typename T>
void foo(T t)
{
    bar(t); // 非限定依赖名称
}
// 在模板实例化点查找
// 考虑ADL（Argument-Dependent Lookup）

// ADL（Argument-Dependent Lookup）
// ADL是C++中的一种特殊查找机制，也称为"Koenig查找"：
namespace N
{
    struct X
    {
    };
    void foo(X) {}
}

void test()
{
    N::X x;
    foo(x); // 通过ADL找到N::foo
}

// 在模板中，ADL对于依赖名称特别重要：
template <typename T>
void process(T value)
{
    print(value); // 通过ADL查找与T相关命名空间中的print
}

// 当前实例化（Current Instantiation）
// 当前实例化是指在模板定义中出现的模板自身或其成员的名称。简单来说，当你在模板内部引用这个模板本身或其成员时，这些引用被视为"当前实例化"。
// 当前实例化的概念对于名称查找很重要，因为它们遵循特殊的规则：
// 当前实例化的名称在模板定义时就能确定（第一阶段查找）
// 它们不被视为依赖名称，即使它们包含模板参数
template <typename T>
class MyClass
{
public:
    // 当前实例化的例子
    MyClass *ptr;               // MyClass指的是MyClass<T>
    void foo(MyClass const &x); // 同样，MyClass指的是MyClass<T>

    // 嵌套类也是当前实例化
    class Nested
    {
        MyClass *ptr; // 这里的MyClass也是指MyClass<T>
    };

    // 非当前实例化的例子
    MyClass<double> *other_ptr; // 这不是当前实例化，而是MyClass<double>
};

// 注入类名（Injected Class Name）
// 注入类名是指C++将类的名称"注入"到类自身的作用域中，使得在类内部可以使用简单的类名来引用这个类。对于模板类，注入类名既可以用作类型名，也可以用作模板名。
// 注入类名提供了一种在类内部引用类自身的简洁方式，特别是对于模板类：
// 可以使用简单的类名（不带模板参数）引用当前实例化
// 也可以使用带模板参数的形式引用特定实例化
template <typename T, int N>
class Array
{
public:
    // 使用注入类名作为类型
    Array *self; // 等价于Array<T,N>*

    // 使用注入类名作为模板名
    Array<T, 10> fixed;      // 使用相同的T但不同的N
    Array<int, N> different; // 使用不同的T但相同的N

    // 完全不同的实例化
    Array<double, 5> another; // T和N都不同

    // 静态方法中的使用
    static Array create()
    { // 返回Array<T,N>
        return Array();
    }
};
// Array* self中的Array是注入类名，等价于Array<T,N>*
// Array<T,10> fixed中的Array也是注入类名，但这里用作模板名
// 两者的关系与区别
// 1.关系：
//      注入类名是实现当前实例化的机制
//      当前实例化通常通过注入类名来引用
// 2.区别：
//      当前实例化是一个概念，指的是模板内部对自身的引用
//      注入类名是一个语言机制，允许在类内部使用简化的名称

// 递归数据结构
template <typename T>
class LinkedList
{
public:
    T data;
    LinkedList *next; // 使用注入类名，等价于LinkedList<T>*

    // 递归方法
    void append(const T &value)
    {
        if (next == nullptr)
        {
            next = new LinkedList(); // 创建相同类型的新节点
            next->data = value;
        }
        else
        {
            next->append(value);
        }
    }
};
